/*
 * ABP.c
 *
 *  Created on: 14/11/2012
 *      Author: julian
 */
#include <errno.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>

#include "ABP.h"
#include "message.h"
#include "posix_mq_utils.h"

static pthread_key_t current_var_key;
static pthread_once_t key_once = PTHREAD_ONCE_INIT;

static void make_key() {
    pthread_key_create(&current_var_key, NULL);
}

void abpInit() {

    pthread_once(&key_once, make_key);

}

void abpSpecific(uint8_t *current) {

    pthread_setspecific(current_var_key, current);

}

int abpOut(struct msg_t *msg, wpan_node_t *node) {

    struct msg_buf cbuf;
    //struct msg_t cbuf;
    uint8_t tries = 0;
    uint16_t prio = 0;

    uint8_t* current_bit_p = (uint8_t*) pthread_getspecific(current_var_key);

    if (*(current_bit_p) == 0) {
        msg->options |= ABP_BIT;
        *(current_bit_p) |= ABP_BIT;
    } else {
        msg->options &= ~ABP_BIT;
        *(current_bit_p) = 0;
    }

    while (tries < ABP_MAX_RETRIES+1) { //TODO YOU CHANGED THIS NOW TEST IT

        if (sendPacket(msg, node->adress16, node->adress64) == -1) {
#ifdef ABP_DEBUG
            fprintf(stderr,"ABP_out:sendPacket.Error al enviar mensaje");
#endif
            ++tries; // error sending in lower layers
        } else {

            if (pmsgq_receive(node->msqid, &cbuf, sizeof(cbuf),
                    (unsigned int*) &prio, ABP_TIMEOUT, 0) == -1) {
//              if (pmsgq_receive(node->msqid, &cbuf, sizeof(struct msg_t),
//                      (unsigned int*) &prio, ABP_TIMEOUT, 0) == -1) {
#ifdef ABP_DEBUG
                perror("ABP_out:pmsgq_recv.Error al retirar ACK de la cola de mensajes");
#endif
                //break;
                //timeout
                ++tries;
            } else {

                if (prio == ACK) {
                    if ((cbuf.msg.options & ABP_BIT)
                            != (*(current_bit_p) & ABP_BIT)) {
//                        if ((cbuf.options & ABP_BIT)
//                                != (*(current_bit_p) & ABP_BIT)) {
                        ++tries; // not the ACK i'm waiting for
                    } else {
                        tries = 0;
                        return (0);
                    }
                } else {
                    ++tries; // not the frame i'm waiting for
                }
            }
        }
    }
    tries = 0;
    return (-1);

}
